from PyQt4 import QtGui
import syntax_python

def format(formatstr):
    """Return a QTextCharFormat with the given attributes.
    """
    style=formatstr.split(',')
    
    color = QtGui.QColor()
    color.setNamedColor(style[0])

    format = QtGui.QTextCharFormat()
    format.setForeground(color)
    for item in style[1:]:
        item=item.strip()
        if item=='bold':
            format.setFontWeight(QtGui.QFont.Bold)
        elif item == 'italic':
            format.setFontItalic(True)
        elif item == 'errorline':
            format.setUnderlineStyle(QtGui.QTextCharFormat.SpellCheckUnderline)
            format.setUnderlineColor(color)


    return format

class Highlighter(QtGui.QSyntaxHighlighter):
    formats={
        'string': '#7f007f',
        'comment': '#007F00',
        'unterminated': 'black',
        'keyword': '#00007f,bold',
        'number': '#007f7f',
        'methodname': '#007f7f,bold',
        'classname': '#0000ff,bold',
        'mixedwhitespace': 'red,errorline',
        'differentwhitespace': 'blue,errorline'
        }
        
    
    ## Methods
    def __init__(self,tokenizeFunction,*args):
        QtGui.QSyntaxHighlighter.__init__(self,*args)
        self.tokenizeFunction = tokenizeFunction
    def setFormatByDescription(self,start,length,description):
        #TODO: the formats should be cached to improve performance
        formatStr=self.formats.get(description)
        if not formatStr:
            return
        self.setFormat(start,length,format(formatStr))
        
    def highlightBlock(self,line):
        previousState=self.previousBlockState()
    
        self.setCurrentBlockState(0)
        for token in self.tokenizeFunction(line,previousState):
            self.setFormatByDescription(token.start,token.end-token.start,
                token.type)

            #Handle line or string continuation
            if isinstance(token,syntax_python.ContinuationToken):
                self.setCurrentBlockState(token.state)
        

class PyHighlighter(Highlighter):
    def __init__(self,*args):
        Highlighter.__init__(self,syntax_python.tokenizeLine,*args)
        #Init properties
        self.spaceTabs = False
    ## Properties
    @property
    def spaceTabs(self):
        return self._spaceTabs
    
    @spaceTabs.setter
    def spaceTabs(self,value):
        self._spaceTabs = bool(value)
        self.rehighlight()
        
    ## Methods
    def highlightBlock(self,line):
        #Token highlighting
        Highlighter.highlightBlock(self,line)
        
        #Mark indentation problems
        leadingWhitespace=line[:len(line)-len(line.lstrip())]
        if '\t' in leadingWhitespace and ' ' in leadingWhitespace:
            #Mixed tabs/spaces
            self.setFormatByDescription(0,len(leadingWhitespace),'mixedwhitespace')

        elif ('\t' in leadingWhitespace and self.spaceTabs) or \
            (' ' in leadingWhitespace and not self.spaceTabs):
            #Whitespace differs from document setting
            self.setFormatByDescription(0,len(leadingWhitespace),'differentwhitespace')
